package com.googlecode.asm_ide.gui;

import com.googlecode.asm_ide.compiler.CompileFileJDialog;
import com.googlecode.asm_ide.project.NewProjectJDialog;
import com.googlecode.asm_ide.project.Project;
import com.googlecode.asm_ide.project.ProjectFileFilter;
import com.googlecode.asm_ide.util.ButtonTabComponent;
import com.googlecode.asm_ide.util.CustomFile;
import com.googlecode.asm_ide.util.OperatingSystem;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

/**
 *
 * @author Philipp Hell <philipp@hell.info>
 */
public class MainJFrame extends javax.swing.JFrame implements WindowListener, DocumentListener{

    /**
     * Creates new form MainJFrame
     */
    public MainJFrame() {
        if (OperatingSystem.isMac()) {
            initializeForMac();
        }

        initComponents();

        addWindowListener(this);

        openOpenedProjects();

        newFileJMenuItem.setEnabled(false);
        openFileJMenuItem.setEnabled(false);
        compileProjectJMenuItem.setEnabled(false);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jSplitPane = new javax.swing.JSplitPane();
        projectsJTreeJScrollPane = new javax.swing.JScrollPane();
        projectsJTree = new javax.swing.JTree();
        jTabbedPaneProjects = new javax.swing.JTabbedPane();
        jMenuBar = new javax.swing.JMenuBar();
        fileJMenu = new javax.swing.JMenu();
        newProjectJMenuItem = new javax.swing.JMenuItem();
        newFileJMenuItem = new javax.swing.JMenuItem();
        fileNewJSeparator = new javax.swing.JPopupMenu.Separator();
        saveFileJMenuItem = new javax.swing.JMenuItem();
        openProjectJMenuItem = new javax.swing.JMenuItem();
        openFileJMenuItem = new javax.swing.JMenuItem();
        closeProjectJMenuItem = new javax.swing.JMenuItem();
        editJMenu = new javax.swing.JMenu();
        compileProjectJMenuItem = new javax.swing.JMenuItem();
        compileFileJMenuItem = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("ASM-IDE");
        setMinimumSize(new java.awt.Dimension(800, 600));

        jSplitPane.setDividerLocation(256);
        jSplitPane.setDividerSize(4);

        projectsJTree.setModel(projectsTreeModel);
        projectsJTree.setRootVisible(false);
        projectsJTree.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                projectsJTreeMouseClicked(evt);
            }
        });
        projectsJTreeJScrollPane.setViewportView(projectsJTree);

        jSplitPane.setLeftComponent(projectsJTreeJScrollPane);
        jSplitPane.setRightComponent(jTabbedPaneProjects);

        fileJMenu.setText("File");
        fileJMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fileJMenuActionPerformed(evt);
            }
        });

        newProjectJMenuItem.setText("New Project");
        newProjectJMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newProjectJMenuItemActionPerformed(evt);
            }
        });
        fileJMenu.add(newProjectJMenuItem);

        newFileJMenuItem.setText("New File");
        newFileJMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newFileJMenuItemActionPerformed(evt);
            }
        });
        fileJMenu.add(newFileJMenuItem);
        fileJMenu.add(fileNewJSeparator);

        saveFileJMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
        saveFileJMenuItem.setText("Save File");
        saveFileJMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveFileJMenuItemActionPerformed(evt);
            }
        });
        fileJMenu.add(saveFileJMenuItem);

        openProjectJMenuItem.setText("Open Project");
        openProjectJMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openProjectJMenuItemActionPerformed(evt);
            }
        });
        fileJMenu.add(openProjectJMenuItem);

        openFileJMenuItem.setText("Open File");
        openFileJMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openFileJMenuItemActionPerformed(evt);
            }
        });
        fileJMenu.add(openFileJMenuItem);

        closeProjectJMenuItem.setText("Close Project");
        closeProjectJMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeProjectJMenuItemActionPerformed(evt);
            }
        });
        fileJMenu.add(closeProjectJMenuItem);

        jMenuBar.add(fileJMenu);

        editJMenu.setText("Edit");

        compileProjectJMenuItem.setText("Compile Project");
        compileProjectJMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                compileProjectJMenuItemActionPerformed(evt);
            }
        });
        editJMenu.add(compileProjectJMenuItem);

        compileFileJMenuItem.setText("Compile File");
        compileFileJMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                compileFileJMenuItemActionPerformed(evt);
            }
        });
        editJMenu.add(compileFileJMenuItem);

        jMenuBar.add(editJMenu);

        setJMenuBar(jMenuBar);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(jSplitPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 788, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(jSplitPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 566, Short.MAX_VALUE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void initializeForMac() {
        System.setProperty("apple.laf.useScreenMenuBar", "true");
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedLookAndFeelException ex) {
            Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void newProjectJMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newProjectJMenuItemActionPerformed
        NewProjectJDialog npjd = new NewProjectJDialog(this, true);
        npjd.setVisible(true);
    }//GEN-LAST:event_newProjectJMenuItemActionPerformed

    private void newFileJMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newFileJMenuItemActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_newFileJMenuItemActionPerformed

    private void openProjectJMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openProjectJMenuItemActionPerformed
        openProjectJFileChooser = new JFileChooser();
        openProjectJFileChooser.setFileFilter(new ProjectFileFilter());
        openProjectJFileChooser.setMultiSelectionEnabled(false);
        if (openProjectJFileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            File f = openProjectJFileChooser.getSelectedFile();
            openProject(f.getParent());
        }
    }//GEN-LAST:event_openProjectJMenuItemActionPerformed

    public void openProject(String path) {
        try {
            //Unique check
            Project p;
            XMLDecoder de;
            de = new XMLDecoder(new BufferedInputStream(new FileInputStream(path.concat(OperatingSystem.getDirectorySeparator()).concat("asm-ide-project.xml"))));
            p = (Project) de.readObject();
            p.setLastPath(path);
            de.close();
            addProjectToTree(p);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void openProject(Project p) {
        openProject(p.getLastPath());
    }

    private void addProjectToTree(Project p) {
        DefaultMutableTreeNode projectTreeNode = new DefaultMutableTreeNode(p);
        CustomFile f = new CustomFile(p.getLastPath());
        String[] ls = f.list();
        for (int i = 0; i < ls.length; i++) {
            projectTreeNode.add(exploreProject(new CustomFile(f.getPath().concat(OperatingSystem.getDirectorySeparator()).concat(ls[i]))));
        }
        rootTreeNode.add(projectTreeNode);
        projectsJTree.setModel(new DefaultTreeModel(rootTreeNode));
        if (rootTreeNode.getChildCount() > 0) {
            newFileJMenuItem.setEnabled(true);
            openFileJMenuItem.setEnabled(true);
        }
    }

    private DefaultMutableTreeNode exploreProject(CustomFile file) {
        DefaultMutableTreeNode tn = new DefaultMutableTreeNode(file);
        if (file.isDirectory()) {
            String[] ls = file.list();
            for (int i = 0; i < ls.length; i++) {
                tn.add(exploreProject(new CustomFile(file.getPath().concat(OperatingSystem.getDirectorySeparator()).concat(ls[i]))));
            }
        }
        return tn;
    }

    private void openOpenedProjects() {
        ArrayList<Project> openedProjects;
        File f = new File(SAVED_PROJECTS_FILE_NAME);
        if (f.exists()) {
            try {
                XMLDecoder de = new XMLDecoder(new BufferedInputStream(new FileInputStream(f)));
                openedProjects = (ArrayList<Project>) de.readObject();
                de.close();
                Iterator it = openedProjects.iterator();
                while (it.hasNext()) {
                    Project p = (Project) it.next();
                    File path = new File(p.getLastPath());
                    if (path.exists()) {
                        addProjectToTree(p);
                    }
                }
            } catch (FileNotFoundException ex) {
                Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void saveOpenedProjects() {
        Enumeration e = rootTreeNode.children();
        ArrayList<Project> openedProjects = new ArrayList<Project>();
        while (e.hasMoreElements()) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.nextElement();
            if (node.getLevel() == 1) {
                openedProjects.add((Project) node.getUserObject());
            }
        }
        try {
            XMLEncoder en = new XMLEncoder(new BufferedOutputStream(new FileOutputStream(new File(SAVED_PROJECTS_FILE_NAME))));
            en.writeObject(openedProjects);
            en.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void openTab(CustomFile file) {
        int index = jTabbedPaneProjects.getTabCount();
        boolean fileExists = false;
        for (int i = 0; i < index; i++) {
            ButtonTabComponent btc = (ButtonTabComponent) jTabbedPaneProjects.getTabComponentAt(i);
            System.out.println(btc.getFile().getAbsolutePath());
            if (btc.getFile().getAbsolutePath().equals(file.getAbsolutePath())) {
                fileExists = true;
                jTabbedPaneProjects.setSelectedIndex(i);
            }
        }
        if (!fileExists) {
            JTextArea area = new JTextArea();
            area = checkOpenTextArea(file);
            JScrollPane pane = new JScrollPane(area);
            area.getDocument().addDocumentListener(this);
            jTabbedPaneProjects.add(file.getName(), pane);
            jTabbedPaneProjects.setTabComponentAt(index++, new ButtonTabComponent(this.jTabbedPaneProjects, file));
        }
    }

    private JTextArea checkOpenTextArea(CustomFile file) {
        JTextArea area = new JTextArea();
        String s;
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            try {
                while ((s = br.readLine()) != null) {
                    area.append(s + "\n");
                }
            } catch (IOException ex) {
                Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (FileNotFoundException ex) {
            Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
        return area;
    }
    private CustomFile getOpenedFile(){
        ButtonTabComponent btc = (ButtonTabComponent)jTabbedPaneProjects.getSelectedComponent();
        CustomFile cf = btc.getFile();
        return cf;
    }

    private void openFileJMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openFileJMenuItemActionPerformed
    }//GEN-LAST:event_openFileJMenuItemActionPerformed

    private void closeProjectJMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeProjectJMenuItemActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_closeProjectJMenuItemActionPerformed

    private void compileProjectJMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_compileProjectJMenuItemActionPerformed
        
    }//GEN-LAST:event_compileProjectJMenuItemActionPerformed

    private void compileFileJMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_compileFileJMenuItemActionPerformed
        CompileFileJDialog c = new CompileFileJDialog(this, true);
        c.setVisible(true);
    }//GEN-LAST:event_compileFileJMenuItemActionPerformed

private void projectsJTreeMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_projectsJTreeMouseClicked
    if (evt.getButton() == MouseEvent.BUTTON1 && evt.getClickCount() > 1) {
        TreePath tp = projectsJTree.getPathForLocation(evt.getX(), evt.getY());
        if (tp != null) {
            DefaultMutableTreeNode tn = (DefaultMutableTreeNode) tp.getLastPathComponent();
            if (tn.getLevel() > 1) {
                CustomFile cf = (CustomFile) tn.getUserObject();
                if (!cf.isDirectory()) {
                    openTab(cf);
                }
            }
        }
    }
}//GEN-LAST:event_projectsJTreeMouseClicked

private void fileJMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileJMenuActionPerformed
    
}//GEN-LAST:event_fileJMenuActionPerformed

private void saveFileJMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveFileJMenuItemActionPerformed
    int index = jTabbedPaneProjects.getSelectedIndex();
    if(index != -1){
        saveChanges(index);
    }
}//GEN-LAST:event_saveFileJMenuItemActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuItem closeProjectJMenuItem;
    private javax.swing.JMenuItem compileFileJMenuItem;
    private javax.swing.JMenuItem compileProjectJMenuItem;
    private javax.swing.JMenu editJMenu;
    private javax.swing.JMenu fileJMenu;
    private javax.swing.JPopupMenu.Separator fileNewJSeparator;
    private javax.swing.JMenuBar jMenuBar;
    private javax.swing.JSplitPane jSplitPane;
    private javax.swing.JTabbedPane jTabbedPaneProjects;
    private javax.swing.JMenuItem newFileJMenuItem;
    private javax.swing.JMenuItem newProjectJMenuItem;
    private javax.swing.JMenuItem openFileJMenuItem;
    private javax.swing.JMenuItem openProjectJMenuItem;
    private javax.swing.JTree projectsJTree;
    private javax.swing.JScrollPane projectsJTreeJScrollPane;
    private javax.swing.JMenuItem saveFileJMenuItem;
    // End of variables declaration//GEN-END:variables
    private DefaultMutableTreeNode rootTreeNode = new DefaultMutableTreeNode();
    private TreeModel projectsTreeModel = new DefaultTreeModel(rootTreeNode);
    private JFileChooser openProjectJFileChooser;
    private Project selectedProject;
    private boolean changedText = false;
    private static final String SAVED_PROJECTS_FILE_NAME = "asm-ide-saved-projects.xml";

    @Override
    public void windowOpened(WindowEvent we) {
    }

    @Override
    public void windowClosing(WindowEvent we) {
        saveOpenedProjects();
    }

    @Override
    public void windowClosed(WindowEvent we) {
    }

    @Override
    public void windowIconified(WindowEvent we) {
    }

    @Override
    public void windowDeiconified(WindowEvent we) {
    }

    @Override
    public void windowActivated(WindowEvent we) {
    }

    @Override
    public void windowDeactivated(WindowEvent we) {
    }

    // DocumentListener
    @Override
    public void insertUpdate(DocumentEvent e) {
        int index = jTabbedPaneProjects.getSelectedIndex();
        ButtonTabComponent btc = (ButtonTabComponent)jTabbedPaneProjects.getTabComponentAt(index);
        CustomFile cf = btc.getFile();
        if(!cf.isModified()){
           changeTitle(!cf.isModified());
        }
    }
    
    public void saveChanges(int index){
        ButtonTabComponent btc = (ButtonTabComponent)jTabbedPaneProjects.getTabComponentAt(index);
        if(btc != null){
            if(btc.getFile().isModified()){
                try {
                    changeTitle(false);
                    btc = (ButtonTabComponent)jTabbedPaneProjects.getTabComponentAt(index);
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(btc.getFile())));
                    JTextArea text = (JTextArea) jTabbedPaneProjects.getComponentAt(index);
                    System.out.println(text.getText());
                    bw.write(text.getText());
                    bw.close();
                    btc.getFile().setModified(false);
                } catch (IOException ex) {
                    Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
    
    public void changeTitle(Boolean status){
        int index = jTabbedPaneProjects.getSelectedIndex();
        ButtonTabComponent btc = (ButtonTabComponent) jTabbedPaneProjects.getTabComponentAt(index);
        if (btc != null) {
            if (status) {
                CustomFile cf = new CustomFile(btc.getFile().getAbsolutePath() + " * ");
                cf.setModified(true);
                jTabbedPaneProjects.setTabComponentAt(index, new ButtonTabComponent(jTabbedPaneProjects, cf));
            }else{
                CustomFile cf = new CustomFile(btc.getFile().getAbsolutePath().substring(0, btc.getFile().getAbsolutePath().length()-3));
                cf.setModified(false);
                jTabbedPaneProjects.setTabComponentAt(index, new ButtonTabComponent(jTabbedPaneProjects, cf));
            }
        }
        System.out.println(jTabbedPaneProjects.getTitleAt(index));
        jTabbedPaneProjects.repaint();
        changedText = false;
        System.out.println("Änderungen vorgenommen!");
    }

    @Override
    public void removeUpdate(DocumentEvent e) {
        int index = jTabbedPaneProjects.getSelectedIndex();
        ButtonTabComponent btc = (ButtonTabComponent)jTabbedPaneProjects.getTabComponentAt(index);
        CustomFile cf = btc.getFile();
        if(!cf.isModified()){
           changeTitle(!cf.isModified());
        }
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
        System.out.println("Keine Ahnung wos fia a event!^^");
    }
}